// 根据规定的格式化规则字符串，将msg转化为特定形式输出
// 1.确定格式化规则字符串
// 2.解析格式化规则字符串，确定格式化字符和对应的val存入数组;以此创建不同的格式化子项对象
// 3.多态调用不同的format方法，对msg进行格式化输出

#ifndef __M_FMT_H__
#define __M_FMT_H__

#include "util.hpp"
#include "message.hpp"
#include "level.hpp"
#include <memory>
#include <cassert>
#include <sstream>
#include <vector>

namespace wmhLog
{
    //格式化子项
    class FormatItem
    {
    public:
        using ptr = std::shared_ptr<FormatItem>;
        virtual ~FormatItem() {}
        // 将msg的成员写入到os流中
        virtual void format(std::ostream &os, const message &msg) = 0;
    };

    //主题消息
    class MsgFormatItem : public FormatItem
    {
    public:
        MsgFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << msg._paylog;
        }
    };
    //等级
    class LevelFormatItem : public FormatItem
    {
    public:
        LevelFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << logLevel::toString(msg._level);
        }
    };
    //日志器名称
    class NameFormatItem : public FormatItem
    {
    public:
        NameFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << msg._logger;
        }
    };
    //线程id
    class ThreadFormatItem : public FormatItem
    {
    public:
        ThreadFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << msg._tid;
        }
    };
    //时间
    class TimeFormatItem : public FormatItem
    {
    private:
        std::string _format; // 时间格式
    public:
        TimeFormatItem(const std::string &format = "%H:%M:%S")
            : _format(format)
        {
            if (format.empty())
                _format = "%H:%M:%S";
        }
        virtual void format(std::ostream &os, const message &msg)
        {
            time_t t = msg._ctime;
            struct tm lt;
            localtime_r(&t, &lt); // 将时间戳转化为时间结构tm
            char buffer[32];
            // 将时间按format格式化成特定时间结构保存到buffer里面
            strftime(buffer, sizeof(buffer) - 1, _format.c_str(), &lt);
            os << buffer;
        }
    };
    //文件名
    class CFileFormatItem : public FormatItem
    {
    public:
        CFileFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << msg._file;
        }
    };
    //文件行号
    class CLineFormatItem : public FormatItem
    {
    public:
        CLineFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << msg._line;
        }
    };
    //制表符缩进
    class TabFormatItem : public FormatItem
    {
    public:
        TabFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << "\t";
        }
    };
    //换行
    class NLineFormatItem : public FormatItem
    {
    public:
        NLineFormatItem(const std::string &str = "") {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << "\n";
        }
    };
    //其它
    class OtherFormatItem : public FormatItem
    {
    private:
        std::string _str;

    public:
        OtherFormatItem(const std::string &str = "") : _str(str) {}
        virtual void format(std::ostream &os, const message &msg)
        {
            os << _str;
        }
    };

    //格式化日志类
    class Formatter
    {

    public:
        using ptr=std::shared_ptr<Formatter>;
        Formatter(const std::string& pattern="[%d{%H:%M:%S}][%t][%c][%f:%l][%p]%T%m%n")
            :_pattern(pattern)
        {
            assert(parsePattern());
        }
        //对msg进行格式化
        void format(std::ostream& out,message& msg)
        {
            //遍历数组，调用不同的类处把msg添加到out中
            for(auto& item:_items)
            {
                item->format(out,msg);
            }
        }
        std::string format(message& msg)
        {
            std::stringstream ss;
            format(ss,msg);//调用上述函数
            return ss.str();
        }

    private:
        //对格式化规则字符串pattern进行解析
        //ab%%c[%d{%H:%M:%S}][%p]%T%m%n
        bool parsePattern()
        {
            //1.对格式化规则子字符串进行解析
            std::vector<std::pair<std::string,std::string>> fmt_arr;
            size_t pos=0;
            std::string key,val;
            while (pos<_pattern.size())
            {
                //1.处理原始字符串--判断是否是%，不是就是原始字符：如ab
                if(_pattern[pos] !='%')
                {
                    val.push_back(_pattern[pos++]);
                    continue;
                }
                //2.到这说明遇到了%，其中%%处理为一个原始的%字符
                if(pos+1<_pattern.size() && _pattern[pos+1]=='%')
                {
                    val.push_back('%');
                    pos+=2;
                    continue;
                }
                //3.到这里说明%后面是一个格式化字符，保存现有的
                if(val.empty()==false)
                {
                    //保存已经处理过的字符串，未来用于初始化子项
                    fmt_arr.push_back(std::make_pair("",val));
                    val.clear();
                }
                //4.走到这里，表示pos指向%，进行格式化处理
                pos+=1;
                if(pos==_pattern.size())
                {
                    std::cout<<"%之后，没有对应的格式化字符！\n";
                    return false;
                }
                key=_pattern[pos];//添加格式化字符
                pos+=1;
                //处理%d{%H:%M:%S}
                if(pos<_pattern.size() && _pattern[pos]=='{')
                {
                    pos+=1;
                    while (pos<_pattern.size() && _pattern[pos]!='}')
                    {
                        val.push_back(_pattern[pos++]);
                    }
                    //跳出循环要么走到末尾，要么遇到了}
                    //如果走到末尾没有遇到}，出错
                    if(pos==_pattern.size())
                    {
                        std::cout<<"子规则{}匹配出错";
                        return false;
                    }
                    pos+=1;//出循环之后指向}，往后走一步   
                }
                fmt_arr.push_back(std::make_pair(key,val));
                key.clear();
                val.clear();
            }
            //2.根据解析得到的数据初始化格式化子项数组成员
            for(auto& it:fmt_arr)
            {
                _items.push_back(createItem(it.first,it.second));
            }

            return true;
            
        }

        //根据不同的格式化字符，创建不同的格式化子项
        //key:表示格式化字符，如d,t,c
        //val:表示不需要格式化显示的字符串，如abc[]及%H:%M:%S
        FormatItem::ptr createItem(const std::string &key,const std::string& val)
        {
        /*
            %d 日期，包含子格式{%H:%M:%S}
            %t 线程id
            %c 日志器名称
            %f 文件名
            %l 行号
            %p 日志级别
            %T 缩进
            %m 日志消息
            %n 换行
        */
            if(key=="d") return std::make_shared<TimeFormatItem>(val);
            if(key=="t") return std::make_shared<ThreadFormatItem>();
            if(key=="c") return std::make_shared<NameFormatItem>();
            if(key=="f") return std::make_shared<CFileFormatItem>();
            if(key=="l") return std::make_shared<CLineFormatItem>();
            if(key=="p") return std::make_shared<LevelFormatItem>();
            if(key=="T") return std::make_shared<TabFormatItem>();
            if(key=="m") return std::make_shared<MsgFormatItem>();
            if(key=="n") return std::make_shared<NLineFormatItem>();
            if(key=="")  return std::make_shared<OtherFormatItem>(val);
            std::cout<<"没有对应的格式化字符：%"<<key<<std::endl;
            abort();//终止执行，退出
            return FormatItem::ptr();
                
        }
        std::string _pattern;//格式化规则字符串
        std::vector<FormatItem::ptr> _items;//按序保存格式化字符串对应的⼦格式化对象    
    };

}

#endif